home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2008 February / PCWFEB08.iso / Software / Resources / Developers / XAMPP 1.5.4 / Windows installer / xampp-win32-1.5.4-installer.exe / xampp / php / pear / PEAR / ChannelFile.php < prev    next >
Encoding:
PHP Script  |  2005-12-02  |  56.6 KB  |  1,602 lines

  1. <?php
  2. /**
  3.  * PEAR_ChannelFile, the channel handling class
  4.  *
  5.  * PHP versions 4 and 5
  6.  *
  7.  * LICENSE: This source file is subject to version 3.0 of the PHP license
  8.  * that is available through the world-wide-web at the following URI:
  9.  * http://www.php.net/license/3_0.txt.  If you did not receive a copy of
  10.  * the PHP License and are unable to obtain it through the web, please
  11.  * send a note to license@php.net so we can mail you a copy immediately.
  12.  *
  13.  * @category   pear
  14.  * @package    PEAR
  15.  * @author     Greg Beaver <cellog@php.net>
  16.  * @copyright  1997-2005 The PHP Group
  17.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  18.  * @version    CVS: $Id: ChannelFile.php,v 1.73 2005/08/21 05:01:37 cellog Exp $
  19.  * @link       http://pear.php.net/package/PEAR
  20.  * @since      File available since Release 1.4.0a1
  21.  */
  22.  
  23. /**
  24.  * Needed for error handling
  25.  */
  26. require_once 'PEAR/ErrorStack.php';
  27. require_once 'PEAR/XMLParser.php';
  28. require_once 'PEAR/Common.php';
  29.  
  30. /**
  31.  * Error code if the channel.xml <channel> tag does not contain a valid version
  32.  */
  33. define('PEAR_CHANNELFILE_ERROR_NO_VERSION', 1);
  34. /**
  35.  * Error code if the channel.xml <channel> tag version is not supported (version 1.0 is the only supported version,
  36.  * currently
  37.  */
  38. define('PEAR_CHANNELFILE_ERROR_INVALID_VERSION', 2);
  39.  
  40. /**
  41.  * Error code if parsing is attempted with no xml extension
  42.  */
  43. define('PEAR_CHANNELFILE_ERROR_NO_XML_EXT', 3);
  44.  
  45. /**
  46.  * Error code if creating the xml parser resource fails
  47.  */
  48. define('PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER', 4);
  49.  
  50. /**
  51.  * Error code used for all sax xml parsing errors
  52.  */
  53. define('PEAR_CHANNELFILE_ERROR_PARSER_ERROR', 5);
  54.  
  55. /**#@+
  56.  * Validation errors
  57.  */
  58. /**
  59.  * Error code when channel name is missing
  60.  */
  61. define('PEAR_CHANNELFILE_ERROR_NO_NAME', 6);
  62. /**
  63.  * Error code when channel name is invalid
  64.  */
  65. define('PEAR_CHANNELFILE_ERROR_INVALID_NAME', 7);
  66. /**
  67.  * Error code when channel summary is missing
  68.  */
  69. define('PEAR_CHANNELFILE_ERROR_NO_SUMMARY', 8);
  70. /**
  71.  * Error code when channel summary is multi-line
  72.  */
  73. define('PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY', 9);
  74. /**
  75.  * Error code when channel server is missing for xmlrpc or soap protocol
  76.  */
  77. define('PEAR_CHANNELFILE_ERROR_NO_HOST', 10);
  78. /**
  79.  * Error code when channel server is invalid for xmlrpc or soap protocol
  80.  */
  81. define('PEAR_CHANNELFILE_ERROR_INVALID_HOST', 11);
  82. /**
  83.  * Error code when a mirror name is invalid
  84.  */
  85. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRROR', 21);
  86. /**
  87.  * Error code when a mirror type is invalid
  88.  */
  89. define('PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE', 22);
  90. /**
  91.  * Error code when an attempt is made to generate xml, but the parsed content is invalid
  92.  */
  93. define('PEAR_CHANNELFILE_ERROR_INVALID', 23);
  94. /**
  95.  * Error code when an empty package name validate regex is passed in
  96.  */
  97. define('PEAR_CHANNELFILE_ERROR_EMPTY_REGEX', 24);
  98. /**
  99.  * Error code when a <function> tag has no version
  100.  */
  101. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION', 25);
  102. /**
  103.  * Error code when a <function> tag has no name
  104.  */
  105. define('PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME', 26);
  106. /**
  107.  * Error code when a <validatepackage> tag has no name
  108.  */
  109. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME', 27);
  110. /**
  111.  * Error code when a <validatepackage> tag has no version attribute
  112.  */
  113. define('PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION', 28);
  114. /**
  115.  * Error code when a mirror does not exist but is called for in one of the set*
  116.  * methods.
  117.  */
  118. define('PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND', 32);
  119. /**
  120.  * Error code when a server port is not numeric
  121.  */
  122. define('PEAR_CHANNELFILE_ERROR_INVALID_PORT', 33);
  123. /**
  124.  * Error code when <static> contains no version attribute
  125.  */
  126. define('PEAR_CHANNELFILE_ERROR_NO_STATICVERSION', 34);
  127. /**
  128.  * Error code when <baseurl> contains no type attribute in a <rest> protocol definition
  129.  */
  130. define('PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE', 35);
  131. /** 
  132.  * Error code when a mirror is defined and the channel.xml represents the __uri pseudo-channel
  133.  */
  134. define('PEAR_CHANNELFILE_URI_CANT_MIRROR', 36);
  135. /** 
  136.  * Error code when ssl attribute is present and is not "yes"
  137.  */
  138. define('PEAR_CHANNELFILE_ERROR_INVALID_SSL', 37);
  139. /**#@-*/
  140.  
  141. /**
  142.  * Mirror types allowed.  Currently only internet servers are recognized.
  143.  */
  144. $GLOBALS['_PEAR_CHANNELS_MIRROR_TYPES'] =  array('server');
  145.  
  146.  
  147. /**
  148.  * The Channel handling class
  149.  *
  150.  * @category   pear
  151.  * @package    PEAR
  152.  * @author     Greg Beaver <cellog@php.net>
  153.  * @copyright  1997-2005 The PHP Group
  154.  * @license    http://www.php.net/license/3_0.txt  PHP License 3.0
  155.  * @version    Release: 1.4.5
  156.  * @link       http://pear.php.net/package/PEAR
  157.  * @since      Class available since Release 1.4.0a1
  158.  */
  159. class PEAR_ChannelFile {
  160.     /**
  161.      * @access private
  162.      * @var PEAR_ErrorStack
  163.      * @access private
  164.      */
  165.     var $_stack;
  166.     
  167.     /**
  168.      * Supported channel.xml versions, for parsing
  169.      * @var array
  170.      * @access private
  171.      */
  172.     var $_supportedVersions = array('1.0');
  173.  
  174.     /**
  175.      * Parsed channel information
  176.      * @var array
  177.      * @access private
  178.      */
  179.     var $_channelInfo;
  180.  
  181.     /**
  182.      * index into the subchannels array, used for parsing xml
  183.      * @var int
  184.      * @access private
  185.      */
  186.     var $_subchannelIndex;
  187.  
  188.     /**
  189.      * index into the mirrors array, used for parsing xml
  190.      * @var int
  191.      * @access private
  192.      */
  193.     var $_mirrorIndex;
  194.     
  195.     /**
  196.      * Flag used to determine the validity of parsed content
  197.      * @var boolean
  198.      * @access private
  199.      */
  200.     var $_isValid = false;
  201.  
  202.     function PEAR_ChannelFile()
  203.     {
  204.         $this->_stack = &new PEAR_ErrorStack('PEAR_ChannelFile');
  205.         $this->_stack->setErrorMessageTemplate($this->_getErrorMessage());
  206.         $this->_isValid = false;
  207.     }
  208.     
  209.     /**
  210.      * @return array
  211.      * @access protected
  212.      */
  213.     function _getErrorMessage()
  214.     {
  215.         return
  216.             array(
  217.                 PEAR_CHANNELFILE_ERROR_INVALID_VERSION =>
  218.                     'While parsing channel.xml, an invalid version number "%version% was passed in, expecting one of %versions%',
  219.                 PEAR_CHANNELFILE_ERROR_NO_VERSION =>
  220.                     'No version number found in <channel> tag',
  221.                 PEAR_CHANNELFILE_ERROR_NO_XML_EXT =>
  222.                     '%error%',
  223.                 PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER =>
  224.                     'Unable to create XML parser',
  225.                 PEAR_CHANNELFILE_ERROR_PARSER_ERROR =>
  226.                     '%error%',
  227.                 PEAR_CHANNELFILE_ERROR_NO_NAME =>
  228.                     'Missing channel name',
  229.                 PEAR_CHANNELFILE_ERROR_INVALID_NAME =>
  230.                     'Invalid channel %tag% "%name%"',
  231.                 PEAR_CHANNELFILE_ERROR_NO_SUMMARY =>
  232.                     'Missing channel summary',
  233.                 PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY =>
  234.                     'Channel summary should be on one line, but is multi-line',
  235.                 PEAR_CHANNELFILE_ERROR_NO_HOST =>
  236.                     'Missing channel server for %type% server',
  237.                 PEAR_CHANNELFILE_ERROR_INVALID_HOST =>
  238.                     'Server name "%server%" is invalid for %type% server',
  239.                 PEAR_CHANNELFILE_ERROR_INVALID_MIRROR =>
  240.                     'Invalid mirror name "%name%", mirror type %type%',
  241.                 PEAR_CHANNELFILE_ERROR_INVALID_MIRRORTYPE =>
  242.                     'Invalid mirror type "%type%"',
  243.                 PEAR_CHANNELFILE_ERROR_INVALID =>
  244.                     'Cannot generate xml, contents are invalid',
  245.                 PEAR_CHANNELFILE_ERROR_EMPTY_REGEX =>
  246.                     'packagenameregex cannot be empty',
  247.                 PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION =>
  248.                     '%parent% %protocol% function has no version',
  249.                 PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME =>
  250.                     '%parent% %protocol% function has no name',
  251.                 PEAR_CHANNELFILE_ERROR_NOBASEURLTYPE =>
  252.                     '%parent% rest baseurl has no type',
  253.                 PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME =>
  254.                     'Validation package has no name in <validatepackage> tag',
  255.                 PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION =>
  256.                     'Validation package "%package%" has no version',
  257.                 PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND =>
  258.                     'Mirror "%mirror%" does not exist',
  259.                 PEAR_CHANNELFILE_ERROR_INVALID_PORT =>
  260.                     'Port "%port%" must be numeric',
  261.                 PEAR_CHANNELFILE_ERROR_NO_STATICVERSION =>
  262.                     '<static> tag must contain version attribute',
  263.                 PEAR_CHANNELFILE_URI_CANT_MIRROR =>
  264.                     'The __uri pseudo-channel cannot have mirrors',
  265.                 PEAR_CHANNELFILE_ERROR_INVALID_SSL =>
  266.                     '%server% has invalid ssl attribute "%ssl%" can only be yes or not present',
  267.             );
  268.     }
  269.  
  270.     /**
  271.      * @param string contents of package.xml file
  272.      * @return bool success of parsing
  273.      */
  274.     function fromXmlString($data)
  275.     {
  276.         if (preg_match('/<channel\s+version="([0-9]+\.[0-9]+)"/', $data, $channelversion)) {
  277.             if (!in_array($channelversion[1], $this->_supportedVersions)) {
  278.                 $this->_stack->push(PEAR_CHANNELFILE_ERROR_INVALID_VERSION, 'error',
  279.                     array('version' => $channelversion[1]));
  280.                 return false;
  281.             }
  282.             $parser = new PEAR_XMLParser;
  283.             $result = $parser->parse($data);
  284.             if ($result !== true) {
  285.                 if ($result->getCode() == 1) {
  286.                     $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_XML_EXT, 'error',
  287.                         array('error' => $error));
  288.                 } else {
  289.                     $this->_stack->push(PEAR_CHANNELFILE_ERROR_CANT_MAKE_PARSER, 'error');
  290.                 }
  291.                 return false;
  292.             }
  293.             $this->_channelInfo = $parser->getData();
  294.             return true;
  295.         } else {
  296.             $this->_stack->push(PEAR_CHANNELFILE_ERROR_NO_VERSION, 'error', array('xml' => $data));
  297.             return false;
  298.         }
  299.     }
  300.     
  301.     /**
  302.      * @return array
  303.      */
  304.     function toArray()
  305.     {
  306.         if (!$this->_isValid && !$this->validate()) {
  307.             return false;
  308.         }
  309.         return $this->_channelInfo;
  310.     }
  311.     
  312.     /**
  313.      * @param array
  314.      * @static
  315.      * @return PEAR_ChannelFile|false false if invalid
  316.      */
  317.     function &fromArray($data, $compatibility = false, $stackClass = 'PEAR_ErrorStack')
  318.     {
  319.         $a = new PEAR_ChannelFile($compatibility, $stackClass);
  320.         $a->_fromArray($data);
  321.         if (!$a->validate()) {
  322.             $a = false;
  323.             return $a;
  324.         }
  325.         return $a;
  326.     }
  327.     
  328.     /**
  329.      * @param array
  330.      * @access private
  331.      */
  332.     function _fromArray($data)
  333.     {
  334.         $this->_channelInfo = $data;
  335.     }
  336.     
  337.     /**
  338.      * Wrapper to {@link PEAR_ErrorStack::getErrors()}
  339.      * @param boolean determines whether to purge the error stack after retrieving
  340.      * @return array
  341.      */
  342.     function getErrors($purge = false)
  343.     {
  344.         return $this->_stack->getErrors($purge);
  345.     }
  346.  
  347.     /**
  348.      * Unindent given string (?)
  349.      *
  350.      * @param string $str The string that has to be unindented.
  351.      * @return string
  352.      * @access private
  353.      */
  354.     function _unIndent($str)
  355.     {
  356.         // remove leading newlines
  357.         $str = preg_replace('/^[\r\n]+/', '', $str);
  358.         // find whitespace at the beginning of the first line
  359.         $indent_len = strspn($str, " \t");
  360.         $indent = substr($str, 0, $indent_len);
  361.         $data = '';
  362.         // remove the same amount of whitespace from following lines
  363.         foreach (explode("\n", $str) as $line) {
  364.             if (substr($line, 0, $indent_len) == $indent) {
  365.                 $data .= substr($line, $indent_len) . "\n";
  366.             }
  367.         }
  368.         return $data;
  369.     }
  370.  
  371.     /**
  372.      * Parse a channel.xml file.  Expects the name of
  373.      * a channel xml file as input.
  374.      *
  375.      * @param string  $descfile  name of channel xml file
  376.      * @return bool success of parsing
  377.      */
  378.     function fromXmlFile($descfile)
  379.     {
  380.         if (!@is_file($descfile) || !is_readable($descfile) ||
  381.              (!$fp = @fopen($descfile, 'r'))) {
  382.             require_once 'PEAR.php';
  383.             return PEAR::raiseError("Unable to open $descfile");
  384.         }
  385.  
  386.         // read the whole thing so we only get one cdata callback
  387.         // for each block of cdata
  388.         if (function_exists('file_get_contents')) {
  389.             fclose($fp);
  390.             $data = file_get_contents($descfile);
  391.         } else {
  392.             $data = fread($fp, filesize($descfile));
  393.             fclose($fp);
  394.         }
  395.         return $this->fromXmlString($data);
  396.     }
  397.  
  398.     /**
  399.      * Parse channel information from different sources
  400.      *
  401.      * This method is able to extract information about a channel
  402.      * from an .xml file or a string
  403.      *
  404.      * @access public
  405.      * @param  string Filename of the source or the source itself
  406.      * @return bool
  407.      */
  408.     function fromAny($info)
  409.     {
  410.         if (is_string($info) && file_exists($info) && strlen($info) < 255) {
  411.             $tmp = substr($info, -4);
  412.             if ($tmp == '.xml') {
  413.                 $info = $this->fromXmlFile($info);
  414.             } else {
  415.                 $fp = fopen($info, "r");
  416.                 $test = fread($fp, 5);
  417.                 fclose($fp);
  418.                 if ($test == "<?xml") {
  419.                     $info = $this->fromXmlFile($info);
  420.                 }
  421.             }
  422.             if (PEAR::isError($info)) {
  423.                 require_once 'PEAR.php';
  424.                 return PEAR::raiseError($info);
  425.             }
  426.         }
  427.         if (is_string($info)) {
  428.             $info = $this->fromXmlString($info);
  429.         }
  430.         return $info;
  431.     }
  432.  
  433.     /**
  434.      * Return an XML document based on previous parsing and modifications
  435.      *
  436.      * @return string XML data
  437.      *
  438.      * @access public
  439.      */
  440.     function toXml()
  441.     {
  442.         if (!$this->_isValid && !$this->validate()) {
  443.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID);
  444.             return false;
  445.         }
  446.         if (!isset($this->_channelInfo['attribs']['version'])) {
  447.             $this->_channelInfo['attribs']['version'] = '1.0';
  448.         }
  449.         $channelInfo = $this->_channelInfo;
  450.         $ret = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\" ?>\n";
  451.         $ret .= "<channel version=\"" .
  452.             $channelInfo['attribs']['version'] . "\" xmlns=\"http://pear.php.net/channel-1.0\"
  453.   xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"
  454.   xsi:schemaLocation=\"http://pear.php.net/dtd/channel-"
  455.             . $channelInfo['attribs']['version'] . " http://pear.php.net/dtd/channel-" .
  456.             $channelInfo['attribs']['version'] . ".xsd\">
  457.  <name>$channelInfo[name]</name>
  458.  <summary>" . htmlspecialchars($channelInfo['summary'])."</summary>
  459. ";
  460.         if (isset($channelInfo['suggestedalias'])) {
  461.             $ret .= ' <suggestedalias>' . $channelInfo['suggestedalias'] . "</suggestedalias>\n";
  462.         }
  463.         if (isset($channelInfo['validatepackage'])) {
  464.             $ret .= ' <validatepackage version="' .
  465.                 $channelInfo['validatepackage']['attribs']['version']. '">' .
  466.                 htmlspecialchars($channelInfo['validatepackage']['_content']) .
  467.                 "</validatepackage>\n";
  468.         }
  469.         $ret .= " <servers>\n";
  470.         $ret .= '  <primary';
  471.         if (isset($channelInfo['servers']['primary']['attribs']['ssl'])) {
  472.             $ret .= ' ssl="' . $channelInfo['servers']['primary']['attribs']['ssl'] . '"';
  473.         }
  474.         if (isset($channelInfo['servers']['primary']['attribs']['port'])) {
  475.             $ret .= ' port="' . $channelInfo['servers']['primary']['attribs']['port'] . '"';
  476.         }
  477.         $ret .= ">\n";
  478.         if (isset($channelInfo['servers']['primary']['xmlrpc'])) {
  479.             $ret .= $this->_makeXmlrpcXml($channelInfo['servers']['primary']['xmlrpc'], '   ');
  480.         }
  481.         if (isset($channelInfo['servers']['primary']['rest'])) {
  482.             $ret .= $this->_makeRestXml($channelInfo['servers']['primary']['rest'], '   ');
  483.         }
  484.         if (isset($channelInfo['servers']['primary']['soap'])) {
  485.             $ret .= $this->_makeSoapXml($channelInfo['servers']['primary']['soap'], '   ');
  486.         }
  487.         $ret .= "  </primary>\n";
  488.         if (isset($channelInfo['servers']['mirror'])) {
  489.             $ret .= $this->_makeMirrorsXml($channelInfo);
  490.         }
  491.         $ret .= " </servers>\n";
  492.         $ret .= "</channel>";
  493.         return str_replace("\r", "\n", str_replace("\r\n", "\n", $ret));
  494.     }
  495.  
  496.     /**
  497.      * Generate the <xmlrpc> tag
  498.      * @access private
  499.      */
  500.     function _makeXmlrpcXml($info, $indent)
  501.     {
  502.         $ret = $indent . "<xmlrpc";
  503.         if (isset($info['attribs']['path'])) {
  504.             $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
  505.         }
  506.         $ret .= ">\n";
  507.         $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
  508.         $ret .= $indent . "</xmlrpc>\n";
  509.         return $ret;
  510.     }
  511.  
  512.     /**
  513.      * Generate the <soap> tag
  514.      * @access private
  515.      */
  516.     function _makeSoapXml($info, $indent)
  517.     {
  518.         $ret = $indent . "<soap";
  519.         if (isset($info['attribs']['path'])) {
  520.             $ret .= ' path="' . htmlspecialchars($info['attribs']['path']) . '"';
  521.         }
  522.         $ret .= ">\n";
  523.         $ret .= $this->_makeFunctionsXml($info['function'], "$indent ");
  524.         $ret .= $indent . "</soap>\n";
  525.         return $ret;
  526.     }
  527.  
  528.     /**
  529.      * Generate the <rest> tag
  530.      * @access private
  531.      */
  532.     function _makeRestXml($info, $indent)
  533.     {
  534.         $ret = $indent . "<rest>\n";
  535.         if (!isset($info['baseurl'][0])) {
  536.             $info['baseurl'] = array($info['baseurl']);
  537.         }
  538.         foreach ($info['baseurl'] as $url) {
  539.             $ret .= "$indent <baseurl type=\"" . $url['attribs']['type'] . "\"";
  540.             $ret .= ">" . $url['_content'] . "</baseurl>\n";
  541.         }
  542.         $ret .= $indent . "</rest>\n";
  543.         return $ret;
  544.     }
  545.  
  546.     /**
  547.      * Generate the <mirrors> tag
  548.      * @access private
  549.      */
  550.     function _makeMirrorsXml($channelInfo)
  551.     {
  552.         $ret = "";
  553.         if (!isset($channelInfo['servers']['mirror'][0])) {
  554.             $channelInfo['servers']['mirror'] = array($channelInfo['servers']['mirror']);
  555.         }
  556.         foreach ($channelInfo['servers']['mirror'] as $mirror) {
  557.             $ret .= '  <mirror host="' . $mirror['attribs']['host'] . '"';
  558.             if (isset($mirror['attribs']['port'])) {
  559.                 $ret .= ' port="' . $mirror['attribs']['port'] . '"';
  560.             }
  561.             if (isset($mirror['attribs']['ssl'])) {
  562.                 $ret .= ' ssl="' . $mirror['attribs']['ssl'] . '"';
  563.             }
  564.             $ret .= ">\n";
  565.             if (isset($mirror['xmlrpc']) || isset($mirror['soap'])) {
  566.                 if (isset($mirror['xmlrpc'])) {
  567.                     $ret .= $this->_makeXmlrpcXml($mirror['xmlrpc'], '   ');
  568.                 }
  569.                 if (isset($mirror['rest'])) {
  570.                     $ret .= $this->_makeRestXml($mirror['rest'], '   ');
  571.                 }
  572.                 if (isset($mirror['soap'])) {
  573.                     $ret .= $this->_makeSoapXml($mirror['soap'], '   ');
  574.                 }
  575.                 $ret .= "  </mirror>\n";
  576.             } else {
  577.                 $ret .= "/>\n";
  578.             }
  579.         }
  580.         return $ret;
  581.     }
  582.  
  583.     /**
  584.      * Generate the <functions> tag
  585.      * @access private
  586.      */
  587.     function _makeFunctionsXml($functions, $indent, $rest = false)
  588.     {
  589.         $ret = '';
  590.         if (!isset($functions[0])) {
  591.             $functions = array($functions);
  592.         }
  593.         foreach ($functions as $function) {
  594.             $ret .= "$indent<function version=\"" . $function['attribs']['version'] . "\"";
  595.             if ($rest) {
  596.                 $ret .= ' uri="' . $function['attribs']['uri'] . '"';
  597.             }
  598.             $ret .= ">" . $function['_content'] . "</function>\n";
  599.         }
  600.         return $ret;
  601.     }
  602.  
  603.     /**
  604.      * Validation error.  Also marks the object contents as invalid
  605.      * @param error code
  606.      * @param array error information
  607.      * @access private
  608.      */
  609.     function _validateError($code, $params = array())
  610.     {
  611.         $this->_stack->push($code, 'error', $params);
  612.         $this->_isValid = false;
  613.     }
  614.  
  615.     /**
  616.      * Validation warning.  Does not mark the object contents invalid.
  617.      * @param error code
  618.      * @param array error information
  619.      * @access private
  620.      */
  621.     function _validateWarning($code, $params = array())
  622.     {
  623.         $this->_stack->push($code, 'warning', $params);
  624.     }
  625.  
  626.     /**
  627.      * Validate parsed file.
  628.      *
  629.      * @access public
  630.      * @return boolean
  631.      */
  632.     function validate()
  633.     {
  634.         $this->_isValid = true;
  635.         $info = $this->_channelInfo;
  636.         if (empty($info['name'])) {
  637.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_NAME);
  638.         } elseif (!$this->validChannelServer($info['name'])) {
  639.             if ($info['name'] != '__uri') {
  640.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME, array('tag' => 'name',
  641.                     'name' => $info['name']));
  642.             }
  643.         }
  644.         if (empty($info['summary'])) {
  645.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  646.         } elseif (strpos(trim($info['summary']), "\n") !== false) {
  647.             $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  648.                 array('summary' => $info['summary']));
  649.         }
  650.         if (isset($info['suggestedalias'])) {
  651.             if (!$this->validChannelServer($info['suggestedalias'])) {
  652.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  653.                     array('tag' => 'suggestedalias', 'name' =>$info['suggestedalias']));
  654.             }
  655.         }
  656.         if (isset($info['localalias'])) {
  657.             if (!$this->validChannelServer($info['localalias'])) {
  658.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  659.                     array('tag' => 'localalias', 'name' =>$info['localalias']));
  660.             }
  661.         }
  662.         if (isset($info['validatepackage'])) {
  663.             if (!isset($info['validatepackage']['_content'])) {
  664.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_NAME);
  665.             }
  666.             if (!isset($info['validatepackage']['attribs']['version'])) {
  667.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NOVALIDATE_VERSION,
  668.                     array('package' => @$info['validatepackage']['_content']));
  669.             }
  670.         }
  671.         if (isset($info['servers']['primary']['attribs']['port']) &&
  672.               !is_numeric($info['servers']['primary']['attribs']['port'])) {
  673.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_PORT,
  674.                 array('port' => $info['servers']['primary']['attribs']['port']));
  675.         }
  676.         if (isset($info['servers']['primary']['attribs']['ssl']) &&
  677.               $info['servers']['primary']['attribs']['ssl'] != 'yes') {
  678.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  679.                 array('ssl' => $info['servers']['primary']['attribs']['ssl'],
  680.                     'server' => $info['name']));
  681.         }
  682.  
  683.         if (isset($info['servers']['primary']['xmlrpc']) &&
  684.               isset($info['servers']['primary']['xmlrpc']['function'])) {
  685.             $this->_validateFunctions('xmlrpc', $info['servers']['primary']['xmlrpc']['function']);
  686.         }
  687.         if (isset($info['servers']['primary']['soap']) &&
  688.               isset($info['servers']['primary']['soap']['function'])) {
  689.             $this->_validateFunctions('soap', $info['servers']['primary']['soap']['function']);
  690.         }
  691.         if (isset($info['servers']['primary']['rest']) &&
  692.               isset($info['servers']['primary']['rest']['baseurl'])) {
  693.             $this->_validateFunctions('rest', $info['servers']['primary']['rest']['baseurl']);
  694.         }
  695.         if (isset($info['servers']['mirror'])) {
  696.             if ($this->_channelInfo['name'] == '__uri') {
  697.                 $this->_validateError(PEAR_CHANNELFILE_URI_CANT_MIRROR);
  698.             }
  699.             if (!isset($info['servers']['mirror'][0])) {
  700.                 $info['servers']['mirror'] = array($info['servers']['mirror']);
  701.             }
  702.             $i = 0;
  703.             foreach ($info['servers']['mirror'] as $mirror) {
  704.                 if (!isset($mirror['attribs']['host'])) {
  705.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_HOST,
  706.                       array('type' => 'mirror'));
  707.                 } elseif (!$this->validChannelServer($mirror['attribs']['host'])) {
  708.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_HOST,
  709.                         array('server' => $mirror['attribs']['host'], 'type' => 'mirror'));
  710.                 }
  711.                 if (isset($mirror['attribs']['ssl']) && $mirror['attribs']['ssl'] != 'yes') {
  712.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_SSL,
  713.                         array('ssl' => $info['ssl'], 'server' => $mirror['attribs']['host']));
  714.                 }
  715.                 if (isset($mirror['xmlrpc'])) {
  716.                     $this->_validateFunctions('xmlrpc',
  717.                         $mirror['xmlrpc']['function'], $mirror['attribs']['host']);
  718.                 }
  719.                 if (isset($mirror['soap'])) {
  720.                     $this->_validateFunctions('soap', $mirror['soap']['function'],
  721.                         $mirror['attribs']['host']);
  722.                 }
  723.                 if (isset($mirror['rest'])) {
  724.                     $this->_validateFunctions('rest', $mirror['rest']['baseurl'],
  725.                         $mirror['attribs']['host']);
  726.                 }
  727.             }
  728.         }
  729.         return $this->_isValid;
  730.     }
  731.  
  732.     /**
  733.      * @param string xmlrpc or soap - protocol name this function applies to
  734.      * @param array the functions
  735.      * @param string the name of the parent element (mirror name, for instance)
  736.      */
  737.     function _validateFunctions($protocol, $functions, $parent = '')
  738.     {
  739.         if (!isset($functions[0])) {
  740.             $functions = array($functions);
  741.         }
  742.         foreach ($functions as $function) {
  743.             if (!isset($function['_content']) || empty($function['_content'])) {
  744.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONNAME,
  745.                     array('parent' => $parent, 'protocol' => $protocol));
  746.             }
  747.             if ($protocol == 'rest') {
  748.                 if (!isset($function['attribs']['type']) ||
  749.                       empty($function['attribs']['type'])) {
  750.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_BASEURLTYPE,
  751.                         array('parent' => $parent, 'protocol' => $protocol));
  752.                 }
  753.             } else {
  754.                 if (!isset($function['attribs']['version']) ||
  755.                       empty($function['attribs']['version'])) {
  756.                     $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_FUNCTIONVERSION,
  757.                         array('parent' => $parent, 'protocol' => $protocol));
  758.                 }
  759.             }
  760.         }
  761.     }
  762.  
  763.     /**
  764.      * Test whether a string contains a valid channel server.
  765.      * @param string $ver the package version to test
  766.      * @return bool
  767.      */
  768.     function validChannelServer($server)
  769.     {
  770.         if ($server == '__uri') {
  771.             return true;
  772.         }
  773.         return (bool) preg_match(PEAR_CHANNELS_SERVER_PREG, $server);
  774.     }
  775.  
  776.     /**
  777.      * @return string|false
  778.      */
  779.     function getName()
  780.     {
  781.         if (isset($this->_channelInfo['name'])) {
  782.             return $this->_channelInfo['name'];
  783.         } else {
  784.             return false;
  785.         }
  786.     }
  787.  
  788.     /**
  789.      * @return string|false
  790.      */
  791.     function getServer()
  792.     {
  793.         if (isset($this->_channelInfo['name'])) {
  794.             return $this->_channelInfo['name'];
  795.         } else {
  796.             return false;
  797.         }
  798.     }
  799.  
  800.     /**
  801.      * @return int|80 port number to connect to
  802.      */
  803.     function getPort($mirror = false)
  804.     {
  805.         if ($mirror) {
  806.             if ($mir = $this->getMirror($mirror)) {
  807.                 if (isset($mir['attribs']['port'])) {
  808.                     return $mir['attribs']['port'];
  809.                 } else {
  810.                     if ($this->getSSL($mirror)) {
  811.                         return 443;
  812.                     }
  813.                     return 80;
  814.                 }
  815.             }
  816.             return false;
  817.         }
  818.         if (isset($this->_channelInfo['servers']['primary']['attribs']['port'])) {
  819.             return $this->_channelInfo['servers']['primary']['attribs']['port'];
  820.         }
  821.         if ($this->getSSL()) {
  822.             return 443;
  823.         }
  824.         return 80;
  825.     }
  826.  
  827.     /**
  828.      * @return bool Determines whether secure sockets layer (SSL) is used to connect to this channel
  829.      */
  830.     function getSSL($mirror = false)
  831.     {
  832.         if ($mirror) {
  833.             if ($mir = $this->getMirror($mirror)) {
  834.                 if (isset($mir['attribs']['ssl'])) {
  835.                     return true;
  836.                 } else {
  837.                     return false;
  838.                 }
  839.             }
  840.             return false;
  841.         }
  842.         if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  843.             return true;
  844.         }
  845.         return false;
  846.     }
  847.  
  848.     /**
  849.      * @return string|false
  850.      */
  851.     function getSummary()
  852.     {
  853.         if (isset($this->_channelInfo['summary'])) {
  854.             return $this->_channelInfo['summary'];
  855.         } else {
  856.             return false;
  857.         }
  858.     }
  859.  
  860.     /**
  861.      * @param string xmlrpc or soap
  862.      * @param string|false mirror name or false for primary server
  863.      */
  864.     function getPath($protocol, $mirror = false)
  865.     {   
  866.         if (!in_array($protocol, array('xmlrpc', 'soap'))) {
  867.             return false;
  868.         }
  869.         if ($mirror) {
  870.             if (!($mir = $this->getMirror($mirror))) {
  871.                 return false;
  872.             }
  873.             if (isset($mir[$protocol]['attribs']['path'])) {
  874.                 return $mir[$protocol]['attribs']['path'];
  875.             } else {
  876.                 return $protocol . '.php';
  877.             }
  878.         } elseif (isset($this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'])) {
  879.             return $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'];
  880.         }
  881.         return $protocol . '.php';
  882.     }
  883.  
  884.     /**
  885.      * @param string protocol type (xmlrpc, soap)
  886.      * @param string Mirror name
  887.      * @return array|false
  888.      */
  889.     function getFunctions($protocol, $mirror = false)
  890.     {
  891.         if ($this->getName() == '__uri') {
  892.             return false;
  893.         }
  894.         if ($protocol == 'rest') {
  895.             $function = 'baseurl';
  896.         } else {
  897.             $function = 'function';
  898.         }
  899.         if ($mirror) {
  900.             if ($mir = $this->getMirror($mirror)) {
  901.                 if (isset($mir[$protocol][$function])) {
  902.                     return $mir[$protocol][$function];
  903.                 }
  904.             }
  905.             return false;
  906.         }
  907.         if (isset($this->_channelInfo['servers']['primary'][$protocol][$function])) {
  908.             return $this->_channelInfo['servers']['primary'][$protocol][$function];
  909.         } else {
  910.             return false;
  911.         }
  912.     }
  913.  
  914.     /**
  915.      * @param string Protocol type
  916.      * @param string Function name (null to return the
  917.      *               first protocol of the type requested)
  918.      * @param string Mirror name, if any
  919.      * @return array
  920.      */
  921.      function getFunction($type, $name = null, $mirror = false)
  922.      {
  923.         $protocols = $this->getFunctions($type, $mirror);
  924.         if (!$protocols) {
  925.             return false;
  926.         }
  927.         foreach ($protocols as $protocol) {
  928.             if ($name === null) {
  929.                 return $protocol;
  930.             }
  931.             if ($protocol['_content'] != $name) {
  932.                 continue;
  933.             }
  934.             return $protocol;
  935.         }
  936.         return false;
  937.      }
  938.  
  939.     /**
  940.      * @param string protocol type
  941.      * @param string protocol name
  942.      * @param string version
  943.      * @param string mirror name
  944.      * @return boolean
  945.      */
  946.     function supports($type, $name = null, $mirror = false, $version = '1.0')
  947.     {
  948.         $protocols = $this->getFunctions($type, $mirror);
  949.         if (!$protocols) {
  950.             return false;
  951.         }
  952.         foreach ($protocols as $protocol) {
  953.             if ($protocol['attribs']['version'] != $version) {
  954.                 continue;
  955.             }
  956.             if ($name === null) {
  957.                 return true;
  958.             }
  959.             if ($protocol['_content'] != $name) {
  960.                 continue;
  961.             }
  962.             return true;
  963.         }
  964.         return false;
  965.     }
  966.  
  967.     /**
  968.      * Determines whether a channel supports Representational State Transfer (REST) protocols
  969.      * for retrieving channel information
  970.      * @param string
  971.      * @return bool
  972.      */
  973.     function supportsREST($mirror = false)
  974.     {
  975.         if ($mirror == $this->_channelInfo['name']) {
  976.             $mirror = false;
  977.         }
  978.         if ($mirror) {
  979.             if ($mir = $this->getMirror($mirror)) {
  980.                 return isset($mir['rest']);
  981.             }
  982.             return false;
  983.         }
  984.         return isset($this->_channelInfo['servers']['primary']['rest']);
  985.     }
  986.  
  987.     /**
  988.      * Get the URL to access a base resource.
  989.      *
  990.      * Hyperlinks in the returned xml will be used to retrieve the proper information
  991.      * needed.  This allows extreme extensibility and flexibility in implementation
  992.      * @param string Resource Type to retrieve
  993.      */
  994.     function getBaseURL($resourceType, $mirror = false)
  995.     {
  996.         if ($mirror == $this->_channelInfo['name']) {
  997.             $mirror = false;
  998.         }
  999.         if ($mirror) {
  1000.             if ($mir = $this->getMirror($mirror)) {
  1001.                 $rest = $mir['rest'];
  1002.             } else {
  1003.                 return false;
  1004.             }
  1005.             $server = $mirror;
  1006.         } else {
  1007.             $rest = $this->_channelInfo['servers']['primary']['rest'];
  1008.             $server = $this->getServer();
  1009.         }
  1010.         if (!isset($rest['baseurl'][0])) {
  1011.             $rest['baseurl'] = array($rest['baseurl']);
  1012.         }
  1013.         foreach ($rest['baseurl'] as $baseurl) {
  1014.             if (strtolower($baseurl['attribs']['type']) == strtolower($resourceType)) {
  1015.                 return $baseurl['_content'];
  1016.             }
  1017.         }
  1018.         return false;
  1019.     }
  1020.  
  1021.     /**
  1022.      * Since REST does not implement RPC, provide this as a logical wrapper around
  1023.      * resetFunctions for REST
  1024.      * @param string|false mirror name, if any
  1025.      */
  1026.     function resetREST($mirror = false)
  1027.     {
  1028.         return $this->resetFunctions('rest', $mirror);
  1029.     }
  1030.  
  1031.     /**
  1032.      * Empty all protocol definitions
  1033.      * @param string protocol type (xmlrpc, soap)
  1034.      * @param string|false mirror name, if any
  1035.      */
  1036.     function resetFunctions($type, $mirror = false)
  1037.     {
  1038.         if ($mirror) {
  1039.             if (isset($this->_channelInfo['servers']['mirror'])) {
  1040.                 $mirrors = $this->_channelInfo['servers']['mirror'];
  1041.                 if (!isset($mirrors[0])) {
  1042.                     $mirrors = array($mirrors);
  1043.                 }
  1044.                 foreach ($mirrors as $i => $mir) {
  1045.                     if ($mir['attribs']['host'] == $mirror) {
  1046.                         if (isset($this->_channelInfo['servers']['mirror'][$i][$type])) {
  1047.                             unset($this->_channelInfo['servers']['mirror'][$i][$type]);
  1048.                         }
  1049.                         return true;
  1050.                     }
  1051.                 }
  1052.                 return false;
  1053.             } else {
  1054.                 return false;
  1055.             }
  1056.         } else {
  1057.             if (isset($this->_channelInfo['servers']['primary'][$type])) {
  1058.                 unset($this->_channelInfo['servers']['primary'][$type]);
  1059.             }
  1060.             return true;
  1061.         }
  1062.     }
  1063.  
  1064.     /**
  1065.      * Set a channel's protocols to the protocols supported by pearweb
  1066.      */
  1067.     function setDefaultPEARProtocols($version = '1.0', $mirror = false)
  1068.     {
  1069.         switch ($version) {
  1070.             case '1.0' :
  1071.                 $this->resetFunctions('xmlrpc', $mirror);
  1072.                 $this->resetFunctions('soap', $mirror);
  1073.                 $this->resetREST($mirror);
  1074.                 $this->addFunction('xmlrpc', '1.0', 'logintest', $mirror);
  1075.                 $this->addFunction('xmlrpc', '1.0', 'package.listLatestReleases', $mirror);
  1076.                 $this->addFunction('xmlrpc', '1.0', 'package.listAll', $mirror);
  1077.                 $this->addFunction('xmlrpc', '1.0', 'package.info', $mirror);
  1078.                 $this->addFunction('xmlrpc', '1.0', 'package.getDownloadURL', $mirror);
  1079.                 $this->addFunction('xmlrpc', '1.1', 'package.getDownloadURL', $mirror);
  1080.                 $this->addFunction('xmlrpc', '1.0', 'package.getDepDownloadURL', $mirror);
  1081.                 $this->addFunction('xmlrpc', '1.1', 'package.getDepDownloadURL', $mirror);
  1082.                 $this->addFunction('xmlrpc', '1.0', 'package.search', $mirror);
  1083.                 $this->addFunction('xmlrpc', '1.0', 'channel.listAll', $mirror);
  1084.                 return true;
  1085.             break;
  1086.             default :
  1087.                 return false;
  1088.             break;
  1089.         }
  1090.     }
  1091.     
  1092.     /**
  1093.      * @return array
  1094.      */
  1095.     function getMirrors()
  1096.     {
  1097.         if (isset($this->_channelInfo['servers']['mirror'])) {
  1098.             $mirrors = $this->_channelInfo['servers']['mirror'];
  1099.             if (!isset($mirrors[0])) {
  1100.                 $mirrors = array($mirrors);
  1101.             }
  1102.             return $mirrors;
  1103.         } else {
  1104.             return array();
  1105.         }
  1106.     }
  1107.  
  1108.     /**
  1109.      * Get the unserialized XML representing a mirror
  1110.      * @return array|false
  1111.      */
  1112.     function getMirror($server)
  1113.     {
  1114.         foreach ($this->getMirrors() as $mirror) {
  1115.             if ($mirror['attribs']['host'] == $server) {
  1116.                 return $mirror;
  1117.             }
  1118.         }
  1119.         return false;
  1120.     }
  1121.  
  1122.     /**
  1123.      * @param string
  1124.      * @return string|false
  1125.      * @error PEAR_CHANNELFILE_ERROR_NO_NAME
  1126.      * @error PEAR_CHANNELFILE_ERROR_INVALID_NAME
  1127.      */
  1128.     function setName($name)
  1129.     {
  1130.         return $this->setServer($name);
  1131.     }
  1132.  
  1133.     /**
  1134.      * Set the socket number (port) that is used to connect to this channel
  1135.      * @param integer
  1136.      * @param string|false name of the mirror server, or false for the primary
  1137.      */
  1138.     function setPort($port, $mirror = false)
  1139.     {
  1140.         if ($mirror) {
  1141.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  1142.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1143.                     array('mirror' => $mirror));
  1144.                 return false;
  1145.             }
  1146.             $setmirror = false;
  1147.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  1148.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  1149.                     if ($mirror == $mir['attribs']['host']) {
  1150.                         $this->_channelInfo['servers']['mirror'][$i]['attribs']['port'] = $port;
  1151.                         return true;
  1152.                     }
  1153.                 }
  1154.                 return false;
  1155.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  1156.                 $this->_channelInfo['servers']['mirror']['attribs']['port'] = $port;
  1157.                 $this->_isValid = false;
  1158.                 return true;
  1159.             }
  1160.         }
  1161.         $this->_channelInfo['servers']['primary']['attribs']['port'] = $port;
  1162.         $this->_isValid = false;
  1163.         return true;
  1164.     }
  1165.  
  1166.     /**
  1167.      * Set the socket number (port) that is used to connect to this channel
  1168.      * @param bool Determines whether to turn on SSL support or turn it off
  1169.      * @param string|false name of the mirror server, or false for the primary
  1170.      */
  1171.     function setSSL($ssl = true, $mirror = false)
  1172.     {
  1173.         if ($mirror) {
  1174.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  1175.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1176.                     array('mirror' => $mirror));
  1177.                 return false;
  1178.             }
  1179.             $setmirror = false;
  1180.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  1181.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  1182.                     if ($mirror == $mir['attribs']['host']) {
  1183.                         if (!$ssl) {
  1184.                             if (isset($this->_channelInfo['servers']['mirror'][$i]
  1185.                                   ['attribs']['ssl'])) {
  1186.                                 unset($this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl']);
  1187.                             }
  1188.                         } else {
  1189.                             $this->_channelInfo['servers']['mirror'][$i]['attribs']['ssl'] = 'yes';
  1190.                         }
  1191.                         return true;
  1192.                     }
  1193.                 }
  1194.                 return false;
  1195.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  1196.                 if (!$ssl) {
  1197.                     if (isset($this->_channelInfo['servers']['mirror']['attribs']['ssl'])) {
  1198.                         unset($this->_channelInfo['servers']['mirror']['attribs']['ssl']);
  1199.                     }
  1200.                 } else {
  1201.                     $this->_channelInfo['servers']['mirror']['attribs']['ssl'] = 'yes';
  1202.                 }
  1203.                 $this->_isValid = false;
  1204.                 return true;
  1205.             }
  1206.         }
  1207.         if ($ssl) {
  1208.             $this->_channelInfo['servers']['primary']['attribs']['ssl'] = 'yes';
  1209.         } else {
  1210.             if (isset($this->_channelInfo['servers']['primary']['attribs']['ssl'])) {
  1211.                 unset($this->_channelInfo['servers']['primary']['attribs']['ssl']);
  1212.             }
  1213.         }
  1214.         $this->_isValid = false;
  1215.         return true;
  1216.     }
  1217.  
  1218.     /**
  1219.      * Set the socket number (port) that is used to connect to this channel
  1220.      * @param integer
  1221.      * @param string|false name of the mirror server, or false for the primary
  1222.      */
  1223.     function setPath($protocol, $path, $mirror = false)
  1224.     {
  1225.         if (!in_array($protocol, array('xmlrpc', 'soap'))) {
  1226.             return false;
  1227.         }
  1228.         if ($mirror) {
  1229.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  1230.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1231.                     array('mirror' => $mirror));
  1232.                 return false;
  1233.             }
  1234.             $setmirror = false;
  1235.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  1236.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  1237.                     if ($mirror == $mir['attribs']['host']) {
  1238.                         $this->_channelInfo['servers']['mirror'][$i][$protocol]['attribs']['path'] =
  1239.                             $path;
  1240.                         return true;
  1241.                     }
  1242.                 }
  1243.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1244.                     array('mirror' => $mirror));
  1245.                 return false;
  1246.             } elseif ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  1247.                 $this->_channelInfo['servers']['mirror'][$protocol]['attribs']['path'] = $path;
  1248.                 $this->_isValid = false;
  1249.                 return true;
  1250.             }
  1251.         }
  1252.         $this->_channelInfo['servers']['primary'][$protocol]['attribs']['path'] = $path;
  1253.         $this->_isValid = false;
  1254.         return true;
  1255.     }
  1256.  
  1257.     /**
  1258.      * @param string
  1259.      * @return string|false
  1260.      * @error PEAR_CHANNELFILE_ERROR_NO_SERVER
  1261.      * @error PEAR_CHANNELFILE_ERROR_INVALID_SERVER
  1262.      */
  1263.     function setServer($server, $mirror = false)
  1264.     {
  1265.         if (empty($server)) {
  1266.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SERVER);
  1267.             return false;
  1268.         } elseif (!$this->validChannelServer($server)) {
  1269.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  1270.                 array('tag' => 'name', 'name' => $server));
  1271.             return false;
  1272.         }
  1273.         if ($mirror) {
  1274.             $found = false;
  1275.             foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  1276.                 if ($mirror == $mir['attribs']['host']) {
  1277.                     $found = true;
  1278.                     break;
  1279.                 }
  1280.             }
  1281.             if (!$found) {
  1282.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1283.                     array('mirror' => $mirror));
  1284.                 return false;
  1285.             }
  1286.             $this->_channelInfo['mirror'][$i]['attribs']['host'] = $server;
  1287.             return true;
  1288.         }
  1289.         $this->_channelInfo['name'] = $server;
  1290.         return true;
  1291.     }
  1292.  
  1293.     /**
  1294.      * @param string
  1295.      * @return boolean success
  1296.      * @error PEAR_CHANNELFILE_ERROR_NO_SUMMARY
  1297.      * @warning PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY
  1298.      */
  1299.     function setSummary($summary)
  1300.     {
  1301.         if (empty($summary)) {
  1302.             $this->_validateError(PEAR_CHANNELFILE_ERROR_NO_SUMMARY);
  1303.             return false;
  1304.         } elseif (strpos(trim($summary), "\n") !== false) {
  1305.             $this->_validateWarning(PEAR_CHANNELFILE_ERROR_MULTILINE_SUMMARY,
  1306.                 array('summary' => $summary));
  1307.         }
  1308.         $this->_channelInfo['summary'] = $summary;
  1309.         return true;
  1310.     }
  1311.  
  1312.     /**
  1313.      * @param string
  1314.      * @param boolean determines whether the alias is in channel.xml or local
  1315.      * @return boolean success
  1316.      */
  1317.     function setAlias($alias, $local = false)
  1318.     {
  1319.         if (!$this->validChannelServer($alias)) {
  1320.             $this->_validateError(PEAR_CHANNELFILE_ERROR_INVALID_NAME,
  1321.                 array('tag' => 'suggestedalias', 'name' => $alias));
  1322.             return false;
  1323.         }
  1324.         if ($local) {
  1325.             $this->_channelInfo['localalias'] = $alias;
  1326.         } else {
  1327.             $this->_channelInfo['suggestedalias'] = $alias;
  1328.         }
  1329.         return true;
  1330.     }
  1331.  
  1332.     /**
  1333.      * @return string
  1334.      */
  1335.     function getAlias()
  1336.     {
  1337.         if (isset($this->_channelInfo['localalias'])) {
  1338.             return $this->_channelInfo['localalias'];
  1339.         }
  1340.         if (isset($this->_channelInfo['suggestedalias'])) {
  1341.             return $this->_channelInfo['suggestedalias'];
  1342.         }
  1343.         if (isset($this->_channelInfo['name'])) {
  1344.             return $this->_channelInfo['name'];
  1345.         }
  1346.     }
  1347.  
  1348.     /**
  1349.      * Set the package validation object if it differs from PEAR's default
  1350.      * The class must be includeable via changing _ in the classname to path separator,
  1351.      * but no checking of this is made.
  1352.      * @param string|false pass in false to reset to the default packagename regex
  1353.      * @return boolean success
  1354.      */
  1355.     function setValidationPackage($validateclass, $version)
  1356.     {
  1357.         if (empty($validateclass)) {
  1358.             unset($this->_channelInfo['validatepackage']);
  1359.         }
  1360.         $this->_channelInfo['validatepackage'] = array('_content' => $validateclass);
  1361.         $this->_channelInfo['validatepackage']['attribs'] = array('version' => $version);
  1362.     }
  1363.  
  1364.     /**
  1365.      * Add a protocol to the provides section
  1366.      * @param string protocol type
  1367.      * @param string protocol version
  1368.      * @param string protocol name, if any
  1369.      * @param string mirror name, if this is a mirror's protocol
  1370.      * @return bool
  1371.      */
  1372.     function addFunction($type, $version, $name = '', $mirror = false)
  1373.     {
  1374.         if ($mirror) {
  1375.             return $this->addMirrorFunction($mirror, $type, $version, $name);
  1376.         }
  1377.         $set = array('attribs' => array('version' => $version), '_content' => $name);
  1378.         if (!isset($this->_channelInfo['servers']['primary'][$type]['function'])) {
  1379.             $this->_channelInfo['servers']['primary'][$type]['function'] = $set;
  1380.             $this->_isValid = false;
  1381.             return true;
  1382.         } elseif (!isset($this->_channelInfo['servers']['primary'][$type]['function'][0])) {
  1383.             $this->_channelInfo['servers']['primary'][$type]['function'] = array(
  1384.                 $this->_channelInfo['servers']['primary'][$type]['function']);
  1385.         }
  1386.         $this->_channelInfo['servers']['primary'][$type]['function'][] = $set;
  1387.         return true;
  1388.     }
  1389.     /**
  1390.      * Add a protocol to a mirror's provides section
  1391.      * @param string mirror name (server)
  1392.      * @param string protocol type
  1393.      * @param string protocol version
  1394.      * @param string protocol name, if any
  1395.      */
  1396.     function addMirrorFunction($mirror, $type, $version, $name = '')
  1397.     {
  1398.         $found = false;
  1399.         if (!isset($this->_channelInfo['servers']['mirror'])) {
  1400.             $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1401.                 array('mirror' => $mirror));
  1402.             return false;
  1403.         }
  1404.         $setmirror = false;
  1405.         if (isset($this->_channelInfo['servers']['mirror'][0])) {
  1406.             foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  1407.                 if ($mirror == $mir['attribs']['host']) {
  1408.                     $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  1409.                     break;
  1410.                 }
  1411.             }
  1412.         } else {
  1413.             if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  1414.                 $setmirror = &$this->_channelInfo['servers']['mirror'];
  1415.             }
  1416.         }
  1417.         if (!$setmirror) {
  1418.             $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1419.                 array('mirror' => $mirror));
  1420.             return false;
  1421.         }
  1422.         $set = array('attribs' => array('version' => $version), '_content' => $name);
  1423.         if (!isset($setmirror[$type]['function'])) {
  1424.             $setmirror[$type]['function'] = $set;
  1425.             $this->_isValid = false;
  1426.             return true;
  1427.         } elseif (!isset($setmirror[$type]['function'][0])) {
  1428.             $setmirror[$type]['function'] = array($setmirror[$type]['function']);
  1429.         }
  1430.         $setmirror[$type]['function'][] = $set;
  1431.         $this->_isValid = false;
  1432.         return true;
  1433.     }
  1434.  
  1435.     /**
  1436.      * @param string Resource Type this url links to
  1437.      * @param string URL
  1438.      * @param string|false mirror name, if this is not a primary server REST base URL
  1439.      */
  1440.     function setBaseURL($resourceType, $url, $mirror = false)
  1441.     {
  1442.         if ($mirror) {
  1443.             $found = false;
  1444.             if (!isset($this->_channelInfo['servers']['mirror'])) {
  1445.                 $this->_validateError(PEAR_CHANNELFILE_ERROR_MIRROR_NOT_FOUND,
  1446.                     array('mirror' => $mirror));
  1447.                 return false;
  1448.             }
  1449.             $setmirror = false;
  1450.             if (isset($this->_channelInfo['servers']['mirror'][0])) {
  1451.                 foreach ($this->_channelInfo['servers']['mirror'] as $i => $mir) {
  1452.                     if ($mirror == $mir['attribs']['host']) {
  1453.                         $setmirror = &$this->_channelInfo['servers']['mirror'][$i];
  1454.                         break;
  1455.                     }
  1456.                 }
  1457.             } else {
  1458.                 if ($this->_channelInfo['servers']['mirror']['attribs']['host'] == $mirror) {
  1459.                     $setmirror = &$this->_channelInfo['servers']['mirror'];
  1460.                 }
  1461.             }
  1462.         } else {
  1463.             $setmirror = &$this->_channelInfo['servers']['primary'];
  1464.         }
  1465.         $set = array('attribs' => array('type' => $resourceType), '_content' => $url);
  1466.         if (!isset($setmirror['rest']['baseurl'])) {
  1467.             $setmirror['rest']['baseurl'] = $set;
  1468.             $this->_isValid = false;
  1469.             return true;
  1470.         } elseif (!isset($setmirror['rest']['baseurl'][0])) {
  1471.             $setmirror['rest']['baseurl'] = array($setmirror['rest']['baseurl']);
  1472.         }
  1473.         foreach ($setmirror['rest']['baseurl'] as $i => $url) {
  1474.             if ($url['attribs']['type'] == $resourceType) {
  1475.                 $this->_isValid = false;
  1476.                 $setmirror['rest']['baseurl'][$i] = $set;
  1477.                 return true;
  1478.             }
  1479.         }
  1480.         $setmirror['rest']['baseurl'][] = $set;
  1481.         $this->_isValid = false;
  1482.         return true;
  1483.     }
  1484.  
  1485.     /**
  1486.      * @param string mirror server
  1487.      * @param int mirror http port
  1488.      * @return boolean
  1489.      */
  1490.     function addMirror($server, $port = null)
  1491.     {
  1492.         if ($this->_channelInfo['name'] == '__uri') {
  1493.             return false; // the __uri channel cannot have mirrors by definition
  1494.         }
  1495.         $set = array('attribs' => array('host' => $server));
  1496.         if (is_numeric($port)) {
  1497.             $set['attribs']['port'] = $port;
  1498.         }
  1499.         if (!isset($this->_channelInfo['servers']['mirror'])) {
  1500.             $this->_channelInfo['servers']['mirror'] = $set;
  1501.             return true;
  1502.         } else {
  1503.             if (!isset($this->_channelInfo['servers']['mirror'][0])) {
  1504.                 $this->_channelInfo['servers']['mirror'] =
  1505.                     array($this->_channelInfo['servers']['mirror']);
  1506.             }
  1507.         }
  1508.         $this->_channelInfo['servers']['mirror'][] = $set;
  1509.         return true;
  1510.     }
  1511.  
  1512.     /**
  1513.      * Retrieve the name of the validation package for this channel
  1514.      * @return string|false
  1515.      */
  1516.     function getValidationPackage()
  1517.     {
  1518.         if (!$this->_isValid && !$this->validate()) {
  1519.             return false;
  1520.         }
  1521.         if (!isset($this->_channelInfo['validatepackage'])) {
  1522.             return array('attribs' => array('version' => 'default'),
  1523.                 '_content' => 'PEAR_Validate');
  1524.         }
  1525.         return $this->_channelInfo['validatepackage'];
  1526.     }
  1527.  
  1528.     /**
  1529.      * Retrieve the object that can be used for custom validation
  1530.      * @param string|false the name of the package to validate.  If the package is
  1531.      *                     the channel validation package, PEAR_Validate is returned
  1532.      * @return PEAR_Validate|false false is returned if the validation package
  1533.      *         cannot be located
  1534.      */
  1535.     function &getValidationObject($package = false)
  1536.     {
  1537.         if (!class_exists('PEAR_Validate')) {
  1538.             require_once 'PEAR/Validate.php';
  1539.         }
  1540.         if (!$this->_isValid) {
  1541.             if (!$this->validate()) {
  1542.                 $a = false;
  1543.                 return $a;
  1544.             }
  1545.         }
  1546.         if (isset($this->_channelInfo['validatepackage'])) {
  1547.             if ($package == $this->_channelInfo['validatepackage']) {
  1548.                 // channel validation packages are always validated by PEAR_Validate
  1549.                 $val = &new PEAR_Validate;
  1550.                 return $val;
  1551.             }
  1552.             if (!class_exists(str_replace('.', '_',
  1553.                   $this->_channelInfo['validatepackage']['_content']))) {
  1554.                 if ($this->isIncludeable(str_replace('_', '/',
  1555.                       $this->_channelInfo['validatepackage']['_content']) . '.php')) {
  1556.                     include_once str_replace('_', '/',
  1557.                         $this->_channelInfo['validatepackage']['_content']) . '.php';
  1558.                     $vclass = str_replace('.', '_',
  1559.                         $this->_channelInfo['validatepackage']['_content']);
  1560.                     $val = &new $vclass;
  1561.                 } else {
  1562.                     $a = false;
  1563.                     return $a;
  1564.                 }
  1565.             } else {
  1566.                 $vclass = str_replace('.', '_',
  1567.                     $this->_channelInfo['validatepackage']['_content']);
  1568.                 $val = &new $vclass;
  1569.             }
  1570.         } else {
  1571.             $val = &new PEAR_Validate;
  1572.         }
  1573.         return $val;
  1574.     }
  1575.  
  1576.     function isIncludeable($path)
  1577.     {
  1578.         $possibilities = explode(PATH_SEPARATOR, ini_get('include_path'));
  1579.         foreach ($possibilities as $dir) {
  1580.             if (file_exists($dir . DIRECTORY_SEPARATOR . $path)
  1581.                   && is_readable($dir . DIRECTORY_SEPARATOR . $path)) {
  1582.                 return true;
  1583.             }
  1584.         }
  1585.         return false;
  1586.     }
  1587.  
  1588.     /**
  1589.      * This function is used by the channel updater and retrieves a value set by
  1590.      * the registry, or the current time if it has not been set
  1591.      * @return string
  1592.      */
  1593.     function lastModified()
  1594.     {
  1595.         if (isset($this->_channelInfo['_lastmodified'])) {
  1596.             return $this->_channelInfo['_lastmodified'];
  1597.         }
  1598.         return time();
  1599.     }
  1600. }
  1601. ?>
  1602.